package com.motong.gongdan.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.motong.gongdan.entity.BomInfo;
import com.motong.gongdan.entity.CustomField;
import com.motong.gongdan.entity.Product;
import com.motong.gongdan.enums.ObjectType;
import com.motong.gongdan.mapper.BomInfoMapper;
import com.motong.gongdan.util.ColumnUtils;
import com.motong.gongdan.vo.system.AssemblyWorkOrder.vo.AssemblyDetailProductVo;
import com.motong.gongdan.vo.system.BOM.query.BOMListQuery;
import com.motong.gongdan.vo.system.BOM.query.ListGroupByProductQuery;
import com.motong.gongdan.vo.system.BOM.vo.BOMListVo;
import com.motong.gongdan.vo.system.otherVo.CustomFieldVo;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
public class BomInfoService extends ServiceImpl<BomInfoMapper, BomInfo> {

    @Resource
    private BomInfoMapper bomInfoMapper;

    @Resource
    private CustomFieldService customFieldService;

    /**
     * @param page  分页条件
     * @param query 查询条件
     * @return 物料清单相关数据
     */
    public Page<BOMListVo> getList(Page<BomInfo> page, BOMListQuery query) {
        Page<BOMListVo> data = bomInfoMapper.getList(page, query);
        return data;
    }

    /**
     * @param productIds 商品ids
     * @return 物料清单相关数据
     */
    public List<AssemblyDetailProductVo> getListByProductId(List<Integer> productIds, Integer getChild) {
        String currentDate = new Date().getTime() + "";
        //已查询过的产品id
        List<AssemblyDetailProductVo> bomInfoList;
        if (getChild == 1) {
            Map<Integer, BigDecimal> childIdUsageMap = new HashMap<>(productIds.size());
            productIds.forEach(i -> childIdUsageMap.put(i, BigDecimal.ONE));
            bomInfoList = this.getBomByProductIdsOther(productIds, null, Collections.emptyMap(), Collections.emptyMap(), new ArrayList<>());
            if (!CollectionUtils.isEmpty(bomInfoList)) {
                bomInfoList.forEach(i -> {
                    if (Objects.nonNull(i.getParentLevel())) {
                        String newParentLevel = i.getParentLevel().concat(":").concat(currentDate);
                        i.setParentLevel(newParentLevel);
                    }
                    String newLevel = i.getLevel().concat(":").concat(currentDate);
                    i.setLevel(newLevel);
                });

            }
        } else {
            bomInfoList = bomInfoMapper.getProductListByProductId(productIds);
        }
        ColumnUtils workOrderColumnUtils = new ColumnUtils(customFieldService, ObjectType.workOrder.getCode());
        ColumnUtils productColumnUtils = new ColumnUtils(customFieldService, ObjectType.product.getCode());
        if (!CollectionUtils.isEmpty(bomInfoList)) {
            bomInfoList.forEach(i -> {
                productColumnUtils.getCuColumnsByJsonArray(i.getProductOther());
                Map<Integer, String> customIdValueMap = productColumnUtils.getCustomIdValueMap();
                List<CustomField> relevanceObjectCustomField = workOrderColumnUtils.getCustomFieldList().stream().filter(d -> "relevanceObject".equals(d.getFieldType()) && "product".equals(d.getBusinessObject()))
                        .collect(Collectors.toList());
                List<CustomFieldVo> customFieldVos = new ArrayList<>();
                relevanceObjectCustomField.forEach(d -> {
                    CustomFieldVo customFieldVo = new CustomFieldVo().setCustomFieldId(d.getId()).setValue(i.getProductName().concat("|").concat(i.getProductCode()))
                            .setCustomFieldMess(d);
                    if (StringUtils.hasLength(d.getFillRule())) {
                        List<Map> maps = JSONUtil.toList(d.getFillRule(), Map.class);
                        maps.forEach(e -> {
                            String value = customIdValueMap.get(Convert.toInt(e.get("from")));
                            Integer workOrderCustomFieldId = Convert.toInt(e.get("to"));
                            if (StringUtils.hasLength(value) && Objects.nonNull(workOrderCustomFieldId)) {
                                CustomFieldVo fillCustomFieldVo = new CustomFieldVo().setCustomFieldId(workOrderCustomFieldId)
                                        .setValue(value).setCustomFieldMess(workOrderColumnUtils.getCuIdDataMap().get(workOrderCustomFieldId));
                                customFieldVos.add(fillCustomFieldVo);
                            }
                        });
                    }
                    customFieldVos.add(customFieldVo);
                });
                i.setCustomFieldVos(customFieldVos);
            });
        }

        return CollectionUtils.isEmpty(bomInfoList) ? Collections.emptyList() : bomInfoList;
    }

    /**
     * 获取物料清单列表(按产品分组)
     */
    public Page<Product> getListGroupByProduct(Page<Product> page, ListGroupByProductQuery query) {
        Page<Product> data = bomInfoMapper.getListGroupByProduct(page, query);
        ColumnUtils productColumnUtils = new ColumnUtils(customFieldService, ObjectType.product.getCode());
        data.getRecords().forEach(i -> i.setCustomFieldVos(productColumnUtils.getCuColumnsByJsonArray(i.getOther())));
        return data;
    }

    public List<AssemblyDetailProductVo> getBomByProductIdsOther(List<Integer> productIds, String parentLevel,
                                                                 Map<Integer, BigDecimal> productIdUnitUsMap, Map<Integer, BigDecimal> productIdNumMap,
                                                                 List<String> existPIdLevelCode) {
        List<AssemblyDetailProductVo> tempData = bomInfoMapper.getListByProductId(productIds);
        AtomicInteger atomicInteger = new AtomicInteger(1);
        List<Integer> haveBomProductId = tempData.stream().map(AssemblyDetailProductVo::getProductId).collect(Collectors.toList());
        List<Integer> noBomProductId = productIds.stream().filter(i -> !haveBomProductId.contains(i)).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(noBomProductId)) {
            List<AssemblyDetailProductVo> noBomInfo = bomInfoMapper.getProductListByProductId(noBomProductId);
            tempData.addAll(noBomInfo);
        }
        Map<Integer, AssemblyDetailProductVo> productIdDataMap = new HashMap<>(tempData.size());
        tempData.forEach(i -> productIdDataMap.put(i.getProductId(), i));
        ArrayList<AssemblyDetailProductVo> finalData = new ArrayList<>();
        productIds.forEach(i -> {
            AssemblyDetailProductVo assemblyDetailProductVo = productIdDataMap.get(i);
            if (Objects.nonNull(assemblyDetailProductVo)) {
                int localLevel = atomicInteger.getAndIncrement();
                String realLevel = StringUtils.hasLength(parentLevel) ? (parentLevel.concat(".") + localLevel) : ("" + localLevel);
                String pIdLevelCode = i.toString().concat(":").concat(realLevel);
                boolean isDeathCirculate = false;
                for (String d : existPIdLevelCode) {
                    if (pIdLevelCode.startsWith(d)) {
                        isDeathCirculate = true;
                        break;
                    }
                }
                if (!isDeathCirculate) {
                    existPIdLevelCode.add(pIdLevelCode);
                    BigDecimal unitUsage = productIdUnitUsMap.getOrDefault(i, BigDecimal.ONE);
                    BigDecimal planNum = productIdNumMap.getOrDefault(i, BigDecimal.ONE);
                    assemblyDetailProductVo.setLevel(realLevel).setParentLevel(parentLevel).setUnitUsage(unitUsage).setPlanedNumber(planNum);
                    List<AssemblyDetailProductVo> childData = new ArrayList<>();
                    assemblyDetailProductVo.setChildren(childData);
                    finalData.add(assemblyDetailProductVo);
                    if (haveBomProductId.contains(i)) {
                        String[] childProductArray = assemblyDetailProductVo.getChildProductIds().split(",");
                        String[] unitUsageArray = assemblyDetailProductVo.getUnitUsages().split(",");
                        Map<Integer, BigDecimal> childProductIdUnitUsMap = new HashMap<>(childProductArray.length);
                        Map<Integer, BigDecimal> childProductIdNumMap = new HashMap<>(childProductArray.length);
                        for (int index = 0; index < childProductArray.length; index++) {
                            int childProductId = Integer.parseInt(childProductArray[index]);
                            BigDecimal childUnitUsage = new BigDecimal(unitUsageArray[index]);
                            childProductIdUnitUsMap.put(childProductId, childUnitUsage);
                            childProductIdNumMap.put(childProductId, childUnitUsage.multiply(planNum));
                        }
                        List<Integer> childProductIds = Arrays.stream(assemblyDetailProductVo.getChildProductIds().split(",")).map(Integer::parseInt).collect(Collectors.toList());
                        childData = this.getBomByProductIdsOther(childProductIds, realLevel, childProductIdUnitUsMap, childProductIdNumMap, existPIdLevelCode);
                        if (!CollectionUtils.isEmpty(childData)) {
                            finalData.addAll(childData);
                        }
                    }
                }

            }
        });
        return finalData;
    }


}
